package com.rran.study.chat.server.core;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.rran.study.chat.server.dto.request.ChatMessage;
import com.rran.study.chat.server.core.model.AcceptBean;
import com.rran.study.chat.server.core.repository.AcceptRespository;
import com.rran.study.chat.server.dto.Response;
import io.netty.channel.ChannelHandlerContext;
import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;

import java.lang.reflect.Method;
import java.util.List;
import java.util.Map;
import java.util.regex.Matcher;

/**
 * @author yy
 * @Type AcceptInvoke.java
 * @Desc
 * @date 2020/8/9 18:01
 */
@Component
public class AcceptInvoke<T extends ChatMessage> {

    public Response invoke(JSONObject param, ChannelHandlerContext ctx) throws Exception {
        String messageType = param.getString("messageUrl");
        if (StringUtils.isEmpty(messageType)) {
            throw new RuntimeException("messageUrl字段不能为空");
        }
        AcceptBean acceptBean = getAcceptBean(messageType);
        Method method = acceptBean.getMethod();
        if (acceptBean == null) {
            throw new RuntimeException("message路径不正确");
        }

        Class<?>[] paramTypes = method.getParameterTypes();
        Object[] paramValues = new Object[paramTypes.length];
        Map<String, Integer> paramMap = acceptBean.getParamIndexMapping();
        //容器启动时已经做过判断了，这里只有两种入参 ChatMessage和 ChannelHandlerContext
        if (paramMap.containsKey(ChannelHandlerContext.class.getName())) {
            int index = paramMap.get(ChannelHandlerContext.class.getName());
            paramValues[index] = ctx;
        }
        Class<T> c = getClass(acceptBean.getMethod());
        if (paramMap.containsKey(c.getName())) {
            int index = paramMap.get(c.getName());
            paramValues[index] = JSON.toJavaObject(param, c);
        }
        //反射执行方法
        Object result = method.invoke(acceptBean.getAccept(),paramValues);
        if (result != null) {
            if (!(result instanceof Response)) {
                throw new RuntimeException("返回类必须为Response");
            }
        }
        return (Response) result;
    }


    private AcceptBean getAcceptBean(String messageUrl) {
        List<AcceptBean> acceptBeans = AcceptRespository.getAcceptBeans();

        if (CollectionUtils.isEmpty(acceptBeans)) {
            return null;
        }
        messageUrl = messageUrl.replaceAll("/+", "/");
        for (AcceptBean acceptBean : acceptBeans) {
            try {
                Matcher matcher = acceptBean.getPattern().matcher(messageUrl);
                if (!matcher.matches()) {
                    continue;
                }
                return acceptBean;
            } catch (Exception e) {
                throw e;
            }
        }
        return null;
    }

    private Class getClass(Method method) {
        Class<?>[] paramTypes = method.getParameterTypes();
        for (Class<?> c : paramTypes) {
            if (ChatMessage.class.isAssignableFrom(c)) {
                return c;
            }
        }
        throw new RuntimeException("accept方法参数不正确");
    }
}
